package com.bj.disc.util;

import java.util.concurrent.atomic.AtomicLong;

public class SnowflakeIdGenerator {
    private Object lock = new Object();
    private final AtomicLong sequence = new AtomicLong(0L);
    private static class LazyHolder {
        private static final SnowflakeIdGenerator INSTANCE = new SnowflakeIdGenerator();
    }
    private SnowflakeIdGenerator (){}
    public static final SnowflakeIdGenerator getInstance() {
        return LazyHolder.INSTANCE;
    }

    // 起始时间戳，用于减少生成的ID位数
    private static final long START_TIMESTAMP = 1577808000000L; // 2020-01-01 00:00:00

    // 机器ID所占的位数
    private static final long WORKER_ID_BITS = 10L;

    // 序列号所占的位数
    private static final long SEQUENCE_BITS = 12L;

    // 机器ID的最大值
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);

    // 序列号的最大值
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);

    // 机器ID向左移12位  (12位序列号)
    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;

    // 时间戳向左移22位  (12位序列号+10位机器ID)
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;

    // 上一次生成ID的时间戳
    private static long lastTimestamp = -1L;


    /**
     * 构造函数
     *
     * @param workerId 机器ID (0~1023)
     */

    /**
     * 生成下一个唯一ID
     *
     * @return 唯一ID
     */
    public   long nextId(long workerId) {
        long timestamp = System.currentTimeMillis();
        synchronized (SnowflakeIdGenerator.class) {
            // 使用CAS原子操作保证线程安全
            long currentSequence;
            long nextSequence;
            do {
                currentSequence = sequence.get();
                nextSequence = (currentSequence + 1) & MAX_SEQUENCE;
            } while (!sequence.compareAndSet(currentSequence, nextSequence));

            // 如果是同一时间生成的ID（同一毫秒内），则进行序列号自增
            if (lastTimestamp == timestamp) {
                sequence.set(nextSequence);
                // 当前毫秒内的序列号已经用完，等待下一毫秒再生成
                if (nextSequence == 0) {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else { // 不同时间生成ID，序列号重置为0
                sequence.set(0L);
            }

            // 记录生成的ID时间戳，用于下次生成ID时比较
            lastTimestamp = timestamp;
            // 生成唯一ID
            return (timestamp << TIMESTAMP_SHIFT)
                    | (workerId << WORKER_ID_SHIFT)
                    | nextSequence;
        }


    }

    /**
     * 等待下一个毫秒
     *
     * @param lastTimestamp 上一次生成ID的时间戳
     * @return 当前时间戳
     */
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}